package com.wyl.java.thread_.quit_;

import cn.hutool.core.util.RandomUtil;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 *
 *
 * ExecutorService.submit(Runnable)方法接受一个Runnable作为参数，但是它返回的是一个Future<?>对象，这可能会让一些开发者感到困惑。实际上，这个设计可以带来一些好处。
 *
 * 首先，我们需要明确的是，Runnable表示一个没有返回值的任务，而Callable<V>表示一个有返回值的任务。但是，在使用线程池框架时，我们通常不关心任务的返回值，而是更关心任务是否执行成功、是否超时、是否被取消等状态。因此，线程池框架返回的Future<?>对象中包含了任务的执行状态以及可能的异常信息，而不仅仅是任务的返回值（如果有的话）。
 *
 * 其次，Future<?>对象可以用于控制任务的执行和取消。例如，我们可以通过调用Future.get()方法来阻塞当前线程并等待任务执行完毕，或者通过调用Future.cancel(boolean mayInterruptIfRunning)方法来尝试取消任务的执行。因此，在某些情况下，即使任务没有返回值，也可以通过Future<?>对象来控制任务的执行。
 *
 * 最后，由于ExecutorService.submit(Runnable)方法返回的是一个Future<?>对象，因此可以与其他支持Future接口的API（如Java 8中的CompletableFuture）进行无缝集成，从而进一步提高代码的灵活性和可维护性。
 *
 * 总之，虽然Runnable没有返回值，但是将其与Future<?>接口结合使用可以提高代码的可读性、可维护性和灵活性。
 *
 * @author 吴宇亮 on 2023/3/24 17:19
 */
public class QuitThread02 {

    public static void main(String[] args) {
        Thread thread01 = new Thread(() -> {
            while (true) {
                try {
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println(Thread.currentThread().getName() + ": interrupted");
                        break;
                    }
                    Thread.sleep(RandomUtil.randomLong(500, 1200));
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        });

        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<?> future = executorService.submit(thread01);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main: interrupted");
        // thread01.interrupt(); // 无法中断在线程池中运行的任务
        future.cancel(true); // 要使用future.cancel(true)来中断
        executorService.shutdown();
    }
}
